package games.mapacman.server;

import aa.core.ActorMessage;
import com.agentslab.constants.APIConstants;
import games.mapacman.common.Constants;

import java.sql.SQLException;
import java.util.List;
import java.util.Vector;

import marauroa.common.Log4J;
import marauroa.common.crypto.Hash;
import marauroa.common.game.AccountResult;
import marauroa.common.game.CharacterResult;
import marauroa.common.game.IRPZone;
import marauroa.common.game.RPAction;
import marauroa.common.game.RPObject;
import marauroa.common.game.RPObjectInvalidException;
import marauroa.common.game.RPObjectNotFoundException;
import marauroa.common.game.Result;
import marauroa.server.db.DBTransaction;
import marauroa.server.db.TransactionPool;
import marauroa.server.game.SimulationStats;
import marauroa.server.game.Statistics;
import marauroa.server.game.db.AccountDAO;
import marauroa.server.game.db.CharacterDAO;
import marauroa.server.game.db.DAORegister;
import marauroa.server.game.rp.IRPRuleProcessor;
import marauroa.server.game.rp.RPServerManager;

public class MaPacmanRPRuleProcessor implements IRPRuleProcessor {

    private static final marauroa.common.Logger logger = Log4J.getLogger(MaPacmanRPRuleProcessor.class);
    private MaPacmanRPWorld world = MaPacmanRPWorld.get();
    private Vector<RPObject> chatChanges;
    private Statistics stats;
    private static MaPacmanRPRuleProcessor instance;
        private boolean requestSent = false;

    public static IRPRuleProcessor get() {
        if (instance == null) {
            instance = new MaPacmanRPRuleProcessor();
        }
        return instance;
    }

	public void setContext(RPServerManager rpman) {
		stats = Statistics.getStatistics();
		chatChanges = new Vector<RPObject>();
		world.setStats(getStats());
                long start = System.currentTimeMillis();
		(new MaPacmanZone("start", this.world)).initialize();
		(new MaPacmanZone("orginal", this.world)).initialize();
		(new MaPacmanZone("map1", this.world)).initialize();
		(new MaPacmanZone("small1", this.world)).initialize();
		(new MaPacmanZone("dungeon1", this.world)).initialize();
		(new MaPacmanZone("dungeon2", this.world)).initialize();
                System.err.println("Initialization time: "+(System.currentTimeMillis()-start));
                
                    
                Object[] argsreg=new Object[3];
                argsreg[0]="";
                argsreg[1]="";
                argsreg[2]="";
                ActorMessage am_reg = new ActorMessage(APIConstants.platform.getActorNameOfPlatform(),
                                                        APIConstants.guiActor,
                                                        "startClient",
                                                        argsreg,
                                                        false
                                                        );

                APIConstants.platform.sendMessage(am_reg);
                    
                
                
        logger.debug("MaPacman::MaPacmanRPRuleProcessor::start creating Zones finished");

    }

    public Statistics getStats() {
        return stats;
    }

    public boolean checkGameVersion(String game, String version) {
        if (game.equals(Constants.GAMENAME)
                && version.equals(Constants.VERSION)) {
            return true;
        } else {
            return false;
        }

    }

    public boolean onActionAdd(RPObject object, RPAction action,
            List<RPAction> actionList) {
        // TODO Auto-generated method stub
        return true;
    }

    public void execute(RPObject object, RPAction action) {
        RPObject.ID id = object.getID();

		if (action.get("type").equals(Constants.CHATMESSAGE)) {
			world.get(id).put("text", action.get("content"));
			world.modify(world.get(id));
			chatChanges.add(world.get(id));
		} else if (action.get("type").equals(Constants.CHANGEDIR)) {
            if (world.get(id) == null) {
                world.addPlayer(object);
                
            }
			world.get(id).put("nextdir", action.getInt("content"));
			world.modify(world.get(id));
		}
	}

    synchronized public void beginTurn() {
        // check for chat Messages
        for (RPObject object : chatChanges) {
            if (object.has("text")) {
                object.remove("text");
                world.modify(object);
            }
        }
        chatChanges.clear();

        world.beginTurn();
        SimulationStats.getStatistics().add("nPlayers", "" + world.getPlayers().size());

    }
    synchronized public void endTurn() {
        // TODO Auto-generated method stub
    }

    synchronized public boolean onInit(RPObject object)
            throws RPObjectInvalidException {
        //System.out.println("object "+object);
        if (!object.has("zoneid")) {
            object.put("zoneid", "start");
        }
        //object.put("zoneid", "start");
        if (object.has("text")) {
            object.remove("text");
        }
        object.put("dir", Constants.DIR_NONE);
        object.put("power", 0);
        object.put("nextdir", Constants.DIR_NONE);
        logger.debug("MaPacman::MaPacmanRPRuleProcessor::onInit Player "
                + object.get("name") + " entered");

//                    for (IRPZone RPzone : world) {
//                            MaPacmanZone zone = (MaPacmanZone) RPzone;
//                            if (zone.getName().equals(object.get("zoneid")) &&  zone.getPlayers().size()>50) {
//                                    System.err.println("zone "+zone.getName()+" is overloaded with "+ zone.getPlayers().size()+ "players");
//                                    world.changeZone(object.get("zoneid"), object);
//                                    break;
//                            }
//                    }
                
		world.addPlayer(object);
		world.modify(object);
                
                if (world.getPlayers().size()>5)
                {
                    if (!requestSent){
                        requestSent = true;
                        Object[] argsreg=new Object[1];
                        argsreg[0]="";
                        ActorMessage am_reg = new ActorMessage(APIConstants.platform.getActorNameOfPlatform(),
                                                               APIConstants.guiActor,
                                                               "needResource",
                                                               argsreg,
                                                               false
                                                               );

//                        APIConstants.platform.sendMessage(am_reg);
                    }
                }

                SimulationStats.getStatistics().add("nPlayers", "" + world.getPlayers().size());
                object.put("nplayers", world.getPlayers().size());
		return true;
	}

	synchronized public boolean onExit(RPObject object)
			throws RPObjectNotFoundException {
		world.removePlayer(object.getID());
                SimulationStats.getStatistics().add("nPlayers", "" + world.getPlayers().size());
		return true;
	}

    synchronized public void onTimeout(RPObject object)
            throws RPObjectNotFoundException {
        onExit(object);
    }

    public AccountResult createAccount(String username, String password,
            String email) {
        TransactionPool transactionPool = TransactionPool.get();
        DBTransaction trans = transactionPool.beginWork();
        AccountDAO accountDAO = DAORegister.get().get(AccountDAO.class);
        try {

            if (accountDAO.hasPlayer(trans, username)) {
                // logger.warn("Account already exist: " + username);
                return new AccountResult(Result.FAILED_PLAYER_EXISTS, username);
            }

            accountDAO.addPlayer(trans, username, Hash.hash(password), email);

            transactionPool.commit(trans);
            // logger.info("Account " + username + " created.");

            return new AccountResult(Result.OK_CREATED, username);
        } catch (SQLException e1) {
            // logger.warn("SQL exception while trying to create a new account: ",
            // e1);
            transactionPool.rollback(trans);
            return new AccountResult(Result.FAILED_EXCEPTION, username);
        }
    }

    public CharacterResult createCharacter(String username, String character,
            RPObject tmpl) {
        TransactionPool transactionPool = TransactionPool.get();
        DBTransaction trans = transactionPool.beginWork();
        CharacterDAO characterDAO = DAORegister.get().get(CharacterDAO.class);
        try {
            if (characterDAO.hasCharacter(trans, username, character)) {
                // logger.warn("Character already exist: " + character);
                return new CharacterResult(Result.FAILED_PLAYER_EXISTS,
                        character, tmpl);
            }
            RPObject object = new RPObject();
            object.put("type", Constants.TYPE_PLAYER);
            object.put("name", character);
            object.put("text", "");
            object.put("x", 0);
            object.put("y", 0);
            object.put("dir", -1);
            object.put("score", 0);
            characterDAO.addCharacter(trans, username, character, object);
            transactionPool.commit(trans);
            // logger.info("Character " + character + " created.");
            return new CharacterResult(Result.OK_CREATED, character, object);
        } catch (Exception e1) {
            // logger.warn("SQL exception while trying to create a new character: ",
            // e1);
            transactionPool.rollback(trans);
            return new CharacterResult(Result.FAILED_EXCEPTION, character, tmpl);
        }
    }
}
